package redecolaborativa.server.util;


import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import redecolaborativa.server.excecoes.AssuntoInvalidoException;
import redecolaborativa.server.excecoes.PermissaoNegadaException;
import redecolaborativa.server.objetos.Emprestimo;
import redecolaborativa.server.objetos.Item;
import redecolaborativa.server.sistema.Gerenciador;
import redecolaborativa.server.sistema.Usuario;

public class Visualizador {
	
	/**
	 * Retorna uma String contendo os amigos do usuario passado no parametro.
	 * @param Usuario o qual deseja-se visualizar os amigos.
	 * @return Amigos do usuario passado no parametro.
	 */
	public static String visualizaAmigos(Usuario procurado) {
		String retorno = "";
		List<Usuario> amigos = procurado.gerenteDeAmigos().getAmigos();
		if (!procurado.gerenteDeAmigos().getAmigos().isEmpty()) {
			Iterator<Usuario> it = amigos.iterator();
			while (it.hasNext()) {
				Usuario usuario = it.next();
				retorno += String.format("%s; ", usuario.getLogin());
			} return retorno.substring(0, retorno.length() - 2);
		} return "O usuário não possui amigos";
	}

	/**
	 * Retorna uma String contendo o nome e o login dos amigos do usuario passado no parametro
	 * @param Usuario o qual deseja-se visualizar os amigos
	 * @return Nome e login dos amigos do usuario passado no parametro
	 */
	public static String visualizaAmigosELogin(Usuario usuario) {
		String retorno = "";
		if(!usuario.gerenteDeAmigos().getAmigos().isEmpty()) {
			Iterator<Usuario> it = usuario.gerenteDeAmigos().getAmigos().iterator();
			while (it.hasNext()) {
				Usuario amigo =  it.next();
				retorno += String.format("%s : %s; ", amigo.getNome(), amigo.getLogin());
			} return retorno.substring(0, retorno.length()-2);
		} return "O usuario nao possui amigos";
	}
	
	/**
	 * Visualiza os itens de um usuario.
	 * @param logado Usuario logado no sistema.
	 * @param procurado Usuario do qual se deseja vizualizar os  itens.
	 * @return Os itens de um usuario.
	 * @throws PermissaoNegadaException
	 */
	public static String visualizaItens(Usuario logado, Usuario procurado) throws PermissaoNegadaException {
		if (!procurado.equals(logado) && !procurado.gerenteDeAmigos().contem(logado)) {
			throw new PermissaoNegadaException("O usuário não tem permissão para visualizar estes itens");
		} 
		String retorno = "";
		List<Item> itens = procurado.gerenteDeItens().getItens();
		if(itens.isEmpty()) {
			return "O usuário não possui itens cadastrados";
		} else {
			Iterator<Item> it = itens.iterator();
			while (it.hasNext()) {
				Item item = it.next();
				retorno += String.format("%s; ", item.getNome()); 
			}
		} return retorno.substring(0, retorno.length()-2);
	}
	
	/**
	 * Vizualiza os itens de um amigo de um usuario e seus ids.
	 * @param logado Usuario logado no sistema.
	 * @param procurado Amigo do qual os itens serao mostrados.
	 * @return Os itens de um amigo de um usuario e seus ids.
	 * @throws PermissaoNegadaException
	 */
	public static String visualizaItensComIdDeAmigo(Usuario logado, Usuario procurado) throws PermissaoNegadaException {
		if (!procurado.equals(logado) && !procurado.gerenteDeAmigos().contem(logado)) {
			throw new PermissaoNegadaException("O usuário não tem permissão para visualizar estes itens");
		} return visualizaItensComId(procurado);
	}
	
	/**
	 * Vizualiza os itens de um usuario e seus ids.
	 * @param usuario Usuario logado no sistema.
	 * @return Os itens de um usuario e seus ids.
	 */
	public static String visualizaItensComId(Usuario usuario) {
		String retorno = "";
		List<Item> itens = usuario.gerenteDeItens().getItens();
		if(itens.isEmpty()) {
			retorno = "O usuário não possui itens cadastrados";
		} else {
			Iterator<Item> it = itens.iterator();
			while (it.hasNext()) {
				Item item = it.next();
				retorno += String.format("\nItem: %s | Id do Item: %s", item.getNome(), item.getID());
			}
		} return retorno;
	}
	
	/**
	 * Constroi uma string com os emprestimos nos quais o usuario eh o emprestador.
	 * @return Uma string com os emprestimos nos quais o usuario eh o emprestador.
	 */
	public static String visualizaEmprestimos(Usuario usuario) {
		String retorno = "";
		if(usuario.gerenteDeEmprestimos().getHistoricoEmprestimos().isEmpty()) {
			return "Não há empréstimos deste tipo";
		} else {
			Iterator<Emprestimo> it = usuario.gerenteDeEmprestimos().getHistoricoEmprestimos().iterator();
			while(it.hasNext()) {
				Emprestimo emp = it.next();
				Usuario beneficiado = emp.getBeneficiado();
				Usuario emprestador = emp.getItem().getDono();
				Item item = emp.getItem();
				retorno += String.format("%s-%s:%s:%s; ", emprestador.getLogin(), beneficiado.getLogin(), item.getNome(), emp.andamento());
			}
		} return retorno.substring(0, retorno.length()-2);
	}
	
	/**
	 * Constroi uma string contendo os emprestimos em que o usuario eh o beneficiado.
	 * @param usuario Usuario que contem os emprestimos adquiridos
	 * @return Uma string contendo os emprestimo em que o usuario eh o beneficiado.	
	 */
	public static String visualizaItensAquiridos(Usuario usuario) {
		String retorno = "";
		List<Emprestimo> adquiridos = usuario.gerenteDeEmprestimos().getAdquiridos();
		if(adquiridos.isEmpty()) {
			return "Não há empréstimos deste tipo";
		} else {
			Iterator<Emprestimo> it = adquiridos.iterator();
			while(it.hasNext()) {
				Emprestimo emp = it.next();
				Usuario emprestador = emp.getItem().getDono();
				Item item = emp.getItem();
				retorno += String.format("%s-%s:%s:%s; ", emprestador.getLogin(), usuario.getLogin(), item.getNome(), emp.andamento());
			} 	
		} return retorno.substring(0, retorno.length()-2);
	}

	/**
	 * Constroi uma string contendo os emprestimos em que o usuario eh o emprestador e os que ele eh o beneficiado, nessa ordem.
	 * @param usuario Usuario
	 * @return Uma string contendo os emprestimos em que o usuario eh o emprestador e os que ele eh o beneficiado.
	 */
	public static String concatenaEmprestimos(Usuario usuario) {
		if(visualizaEmprestimos(usuario).equals("Não há empréstimos deste tipo") && visualizaItensAquiridos(usuario).equals("Não há empréstimos deste tipo")) {
			return "Não há empréstimos deste tipo";
		} if(visualizaEmprestimos(usuario).equals("Não há empréstimos deste tipo")) {
			return String.format("%s", visualizaItensAquiridos(usuario));
		} if(visualizaItensAquiridos(usuario).equals("Não há empréstimos deste tipo")) {
			return String.format("%s", visualizaEmprestimos(usuario));
		} return String.format("%s; %s", visualizaEmprestimos(usuario), visualizaItensAquiridos(usuario));
	}
	
	/**
	 * Mensagens da biblioteca organizada por topicos e assuntos.
	 * @param usuario Usuario logado no sistema.
	 * @return String contendo as mensagens
	 */
	public static String visualizaMensagens(Usuario usuario) {
		String retorno = "";
		List<String> tipoMensagem = Util.ordenaAlfabetica(usuario.gerenteDeMsg().getMensagens().keySet());
	
		for(String tipo : tipoMensagem) {
			retorno += String.format("{%s = ", tipo);
			List<String> assuntoMsg = Util.ordenaAlfabetica(usuario.gerenteDeMsg().getMensagens().get(tipo).keySet());
			if(! assuntoMsg.isEmpty()) {
				for(String assunto : assuntoMsg) { 
					retorno += String.format("%s: ", assunto);
					List<String> apoioMsgs = usuario.gerenteDeMsg().getMensagens().get(tipo).get(assunto);
					for(String msg : apoioMsgs) {
						if(apoioMsgs.size() == 1) {
							retorno += String.format("[%s]; ", msg);
						} else if(msg.equals(apoioMsgs.get(apoioMsgs.size() - 1))) {
							retorno += String.format("%s]; ", msg);
						} else {
							retorno += String.format("[%s, ", msg);
						}
					}
				}
			} retorno += "}";
		} return retorno;
	}
	
	/**
	 * Retorna um string contendo as mensagens com o mesmo idTopico.
	 * @param usuario Usuario logado no sistema.
	 * @param idTopico Id do topico desejado.
	 * @return Uma string contendo as mensagens com o mesmo idTopico.
	 * @throws AssuntoInvalidoException 
	 */
	public static String vizualizaMensagensPorId(Usuario usuario, String idTopico) throws AssuntoInvalidoException {
		String retorno = "";
		Iterator<String> itChaveMsg = usuario.gerenteDeMsg().getMensagens().keySet().iterator();
		while (itChaveMsg.hasNext()) {
			String tipo = itChaveMsg.next();
			Iterator<String> itChaveValorMsg = usuario.gerenteDeMsg().getMensagens().get(tipo).keySet().iterator();
			while (itChaveValorMsg.hasNext()) {
				String assunto =  itChaveValorMsg.next();
				if(assunto.equals(idTopico)) {
					Iterator<String> msg = usuario.gerenteDeMsg().getMensagens().get(tipo).get(assunto).iterator();
					while (msg.hasNext()) {
						retorno += (msg.next() + "; ");
					}
				} if(retorno.equals("")) {
					throw new AssuntoInvalidoException("Tópico inexistente");  
				}
			} 
		} return retorno.substring(0, retorno.length()-2);
	}

	/**	
	 * Imprime uma string contendo os itens de um usuario que estão emprestados.
	 * @param usuario Usuario do qual se deseja imprimir os itens que estao emprestados.
	 */
	public static void visualizaItensQueEstaEmprestado(Usuario usuario){
		Iterator<Emprestimo> it = usuario.gerenteDeEmprestimos().getEmprestimos().iterator();
		while (it.hasNext()) {
			Emprestimo emprestimo = it.next();
			System.out.printf("Item: %s - Id Emprestimo: %s\n", emprestimo.getItem().getNome(), emprestimo.getIDEmprestimo());
		}
	}
	
	/**
	 * Visualiza publicacoes de pedidos.
	 */
	public static void visualizaPublicacoesDePedidos() {
		for (String chave: Gerenciador.getInstance().pedidos().keySet()) {
			System.out.println("Id: " + chave + " - Pedido: " + Gerenciador.getInstance().pedidos().get(chave).getItem());
		}
	}
	
	/**
	 * Formula uma string com as solicitacoes de amizade do usuario.
	 * @param logado Usuario logado no sistema.
	 * @return A string com as solicitacoes de amizade.
	 */
	public static String retornaSolicitacoesDeAmizade(Usuario logado) {
		if(logado.gerenteDeAmigos().getSolicitacoesDeAmizade().isEmpty()) {
			return "Não há requisições";
		}
		String requisicoes = "";
		Iterator<Usuario> it = logado.gerenteDeAmigos().getSolicitacoesDeAmizade().iterator();
		while (it.hasNext()) {
			Usuario pendente = it.next();
			requisicoes += String.format("%s; ", pendente.getLogin());
		} return requisicoes.substring(0 , requisicoes.length()-2);
	}

	/**
	 * Formula uma string com as solicitacoes de item do usuario.
	 * @param logado Usuario logado no sistema.
	 * @return A string com as solicitacoes de item.
	 */
	public static String retornaSolicitacoesDeItens(Usuario logado) {
		if(logado.gerenteDeEmprestimos().getSolicitacoesDeEmprestimo().isEmpty()) {
			return "Não há requisições";
		}
		String requisicoes = "";
		Iterator<Emprestimo> it = logado.gerenteDeEmprestimos().getSolicitacoesDeEmprestimo().iterator();
		while (it.hasNext()) {
			Emprestimo pendente = it.next();
			requisicoes += String.format("Nome do item: %s | Id da requisição: %s\n", pendente.getItem().getNome(), pendente.getIDRequisicao());
		} return requisicoes;
	}

	/** Formula uma string com as notificacoes de itens livre para o usuario
	 * @param logado Usuario logado no sistema.
	 * @return A string com as notificacoes de item livre
	 */
	public static String retornaNotificaoDeItemLivre(Usuario logado){
		if (logado.gerenteDeItens().getNotificacoesDeItemLivre().isEmpty()) {
			return "Não há notificacoes";
		}
		String notificacoes = "";
		Iterator<Item> it = logado.gerenteDeItens().getNotificacoesDeItemLivre().iterator();
		while (it.hasNext()) {
			Item item = it.next();
			notificacoes += String.format("%s\n", item.getNome());
		} return notificacoes;
	}

	/**
	 * Formula uma string com as notificacoes de itens devolvidos do usuario.
	 * @param logado Usuario logado no sistema.
	 * @return A string com as notificacoes de itens devolvidos.
	 */
	public static String retornaNotificacoesDeDevolucao(Usuario logado) {
		if (logado.gerenteDeEmprestimos().getNotificacoesDeDevolucao().isEmpty()) {
			return "Não há notificacoes";
		}
		String notificacoes = "";
		Iterator<Item> it = logado.gerenteDeEmprestimos().getNotificacoesDeDevolucao().iterator();
		while (it.hasNext()) {
			Item item = it.next();
			notificacoes += String.format("Nome do item: %s | Id do emprestimo: %s\n", item.getNome(), logado.gerenteDeEmprestimos().getEmprestimo(item).getIDEmprestimo());
		} return notificacoes;
	}
	
	/**
	 * Formula uma string com as notificacoes de requisicao de itens do usuario.
	 * @param logado Usuario logado no sistema.
	 * @return A string com as notificacoes de requisicao de itens.
	 */
	public static String retornaNotificacoesDeRequisicaoDevolucao(Usuario logado) {
		if (logado.gerenteDeEmprestimos().getRequisicoesDeDevolucao().isEmpty()) {
			return "Não há notificacoes"; 
		}
		String notificacoes = "";
		Iterator<Item> it = logado.gerenteDeEmprestimos().getRequisicoesDeDevolucao().iterator();
		while (it.hasNext()) {
			Item item = it.next();
			notificacoes += String.format("Nome do item: %s \n", item.getNome());
		} return notificacoes;
	}
	
	/**
	 * Imprime uma string contendo o resultado de uma pesqueisa por um item.
	 * @param pesquisa Lista de itens a ser impressa.
	 * @return String contendo o resultado da pesquisa.
	 */
	public static String imprimePesquisaItem(List<Item> pesquisa) {
		if (pesquisa.isEmpty()) {
			return "Nenhum item encontrado";
		}
		String retorno = "";
		Iterator<Item> it =  pesquisa.iterator();
		while (it.hasNext()) {
			Item item = it.next();
			retorno += item.getNome() + "; ";
		} return retorno.substring(0, retorno.length()-2);
	}
	
	/**
	 * Imprime uma string contendo o resultado de uma pesquisa por um usuario.
	 * @param pesquisa Listade usuarios a ser impressa.
	 * @return String contendo o resultado da pesquisa.
	 */
	public static String imprimePesquisaUsuario(List<Usuario> pesquisa) {
		String retorno = "";
		Iterator<Usuario> it = pesquisa.iterator();
		while (it.hasNext()) {
			Usuario usuario = it.next();
			retorno += String.format("%s - %s; ", usuario.getNome(), usuario.getEndereco());
		} if(retorno.equals("")) {
			return "";
		} else {
			return retorno.substring(0, retorno.length()-2);
		}
	}
		
	/**
	 * Imprime o ranking de usuarios de acordo com o numero de emprestimos finalizados de cada um.
	 * @param mapa Mapa com chave igual ao numero de emprestimos finalizados de um usuario, e valor igual a uma lista de usuarios com aquele numero de emprestimos finalizados.
	 * @return Uma string contendo o ranking ordenado.
	 */
	public static String imprimeRanking(Map<Integer, List<Usuario>> mapa) {
		String retorno = "";
		List<Integer> listaApoio = new ArrayList<Integer>();
		for(Integer numEmprestimos : mapa.keySet()) {
			listaApoio.add(numEmprestimos);
		} 
		Collections.reverse(listaApoio);
		for(Integer numEmprestimos: listaApoio) {
			List<Usuario> usuApoio = mapa.get(numEmprestimos);
			for(Usuario usuario: usuApoio) {
				if (numEmprestimos.equals(listaApoio.get(listaApoio.size()-1))) {
					retorno += (usuario.getLogin() + " ");
				} else {
					retorno += usuario.getLogin() + "; ";
				}
			}
		} return retorno.substring(0, retorno.length()-1);
	}
	
}